﻿using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using RuoVea.ExDto;
using RuoVea.ExEnum;
using RuoVea.ExSugar;
using RuoVea.ExSugar.Entity;
using RuoVea.ExUtil;
using RuoVea.OmiApi.Config.Entitys;
using System.Data;

namespace BookMarks.Web.Controllers;

[Authorize(Roles = "None")]
public partial class BookmarkController : Controller
{
    /// <summary>
    /// 
    /// </summary>
    private readonly SugarRepository<BorBookmark> _thisRepository;
    private readonly SugarRepository<BorCategory> _categoryRepository;
    private readonly SugarRepository<SysConfig> _configRepository;
    private readonly ICurrentUser _currentUser;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisRepository"></param>
    /// <param name="currentUser"></param>
    /// <param name="categoryRepository"></param>
    /// <param name="configRepository"></param>
    public BookmarkController(SugarRepository<BorBookmark> thisRepository, ICurrentUser currentUser, SugarRepository<BorCategory> categoryRepository, SugarRepository<SysConfig> configRepository)
    {
        _thisRepository = thisRepository;
        _currentUser = currentUser;
        _categoryRepository = categoryRepository;
        _configRepository = configRepository;
    }

    public IActionResult Index()
    {
        return View();
    }

    /// <summary>
    /// 查询所有/分页
    /// </summary>
    /// <returns></returns>
    [HttpPost("bookmark/pages")]
    public async Task<RestfulResult<PageResult<BookmarkDto>>> GetPagesAsync()
    {
        var restful = new RestfulResult<PageResult<BookmarkDto>>() { Code = CodeStatus.OK };
        using var sr = new StreamReader(Request.Body);
        string dataStr = await sr.ReadToEndAsync();
        if (Request.Body.CanSeek)
            Request.Body.Position = 0;
        if (string.IsNullOrWhiteSpace(dataStr))
            throw new Exception("未提供上传数据。请在Request.Body中携带上传数据。");
        BookmarkPageParam? data = JsonConvert.DeserializeObject<BookmarkPageParam>(dataStr);
        data.PageSize = 2000;
        var query = await _thisRepository.AsQueryable()
            .Where(u => u.Creator == _currentUser.UserId)
            .Where(u => u.Component == null)
            .Where(u => u.CategoryId == data.CategoryId)
            .WhereIF(data.Title.NotNullOrWhiteSpace(), u => u.Title.Contains(data.Title))
            .ToPageAsync<BorBookmark, BookmarkDto>(data.PageNo, data.PageSize);

        restful.Data = query;
        return restful;
    }

    #region 添加
    /// <summary>
    /// 添加
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpPost("bookmark/add")]
    public async Task<RestfulResult> AddAsync([FromBody] BookmarkDto data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };
        if (data == null)
        {
            restful.Data = false;
            restful.Message = "没有接收到数据.";
            return restful;
        }
        if (data.CategoryId == null || data.CategoryId <= 0)
        {
            restful.Data = false;
            restful.Message = "没有接收到分类数据.";
            return restful;
        }
        var isExist = await _thisRepository.IsAnyAsync(u => (u.Title == data.Title || u.Url == data.Url) && u.Creator == _currentUser.UserId);
        if (isExist)
        {
            restful.Message = "书签已存在";
            return restful;
        }
        bool result = await _thisRepository.InsertAsync(data.Adapt<BorBookmark>());
        if (result)
        {
            restful.Data = result;
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Message = "添加失败";
            return restful;
        }
    }
    #endregion

    #region 导入添加
    /// <summary>
    /// 导入添加
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpPost("bookmark/adds")]
    public async Task<RestfulResult> AddsAsync([FromBody] List<BookmarkDto> data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };
        if (data == null || !data.Any())
        {
            restful.Data = false;
            restful.Message = "没有接收到数据.";
            return restful;
        }

        var ignoreTitles = RuoVea.ExConfig.AppSettings.app<string>("IgnoreTitles");
        var datas = data.Where(x => !ignoreTitles.Contains(x.Title)).Distinct().ToList();
        var bookmarkData = FlattenBookmarks(datas);


        var titles = bookmarkData.Where(x => x.Type == "folder").Select(x => x.Title).Distinct().ToList();
        var categorys = titles.Select(x => new BorCategory { Name = x, Code = RuoVea.ExUtil.ExString.Str.PinYin(x), Creator = _currentUser.UserId, CreateTime = DateTime.Now, IsDelete = 0, IsDisable = 0, Sort = 20 }).ToList();
        categorys = categorys.Distinct().ToList();
        var x = _categoryRepository.Context.Storageable(categorys)
            .WhereColumns(x => new { x.Name, x.Creator }).ToStorage();
        await x.AsInsertable.ExecuteCommandAsync();


        var links = bookmarkData.Where(x => x.Type == "link").Distinct().ToList();
        var categoryDatas = _categoryRepository.AsQueryable()
            .Where(x => titles.Contains(x.Name) && x.Creator == _currentUser.UserId)
            .Select(x => new BorCategory { Name = x.Name, Id = x.Id }).ToList();

        List<BorBookmark> contents = new();
        foreach (var item in links)
        {
            if (string.IsNullOrWhiteSpace(item.Title) || string.IsNullOrWhiteSpace(item.Url))
                continue;
            var minData = item.Adapt<BorBookmark>();
            minData.CategoryId = categoryDatas.Where(c => c.Name == item.ParentType).Select(c => c.Id).FirstOrDefault();
            minData.Creator = _currentUser.UserId;
            minData.CreateTime = DateTime.Now;
            minData.IsDisable = 0; minData.IsDisable = 0; minData.Sort = 20;
            contents.Add(minData);
        }
        contents = contents.Distinct().ToList();
        var y = _thisRepository.Context.Storageable(contents).WhereColumns(x => new { x.Title, x.Url, x.Creator }).ToStorage();
        bool result = await y.AsInsertable.ExecuteCommandAsync() > 0;

        if (result)
        {
            restful.Data = result;
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Message = "添加失败";
            return restful;
        }
    }

    private List<BookmarkDto> FlattenBookmarks(List<BookmarkDto> bookmarks, string parent = null, List<BookmarkDto> accumulator = null)
    {
        if (accumulator == null)
        {
            accumulator = new List<BookmarkDto>();
        }

        if (bookmarks == null || !bookmarks.Any())
        {
            return accumulator;
        }

        foreach (var item in bookmarks)
        {
            item.ParentType = parent;

            accumulator.Add(item);

            // 只有当子级列表不为空时才递归调用
            if (item.children != null && item.children.Any())
            {
                FlattenBookmarks(item.children, item.Title, accumulator);
            }
        }

        return accumulator;
    }
    #endregion

    #region Itab 导入添加
    /// <summary>
    /// Itab 导入添加
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpPost("bookmark/byitab")]
    public async Task<RestfulResult> AddByItabAsync([FromBody] ItabExportInDto data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };
        if (data == null)
        {
            restful.Data = false;
            restful.Message = "没有接收到数据.";
            return restful;
        }
        string configUrl = RuoVea.ExConfig.AppSettings.app("ITab:configUrl");

        string responseContent = await HttpUtils.HttpGetAsync(configUrl, new Dictionary<string, string> { { "token", data.token },
            { "signaturekey", data.signaturekey }, { "User-Agent", data.useragent }
        });
        if (string.IsNullOrWhiteSpace(responseContent))
        {
            restful.Data = false;
            restful.Message = "没有接收到ITab返回数据.";
            return restful;
        }
        ApiResponse? apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseContent);
        if (apiResponse == null)
        {
            restful.Data = false;
            restful.Message = "ITab返回数据解析失败.";
            return restful;
        }
        if (apiResponse.Code != 200)
        {
            restful.Data = false;
            restful.Message = "没有接收到ITab返回数据." + apiResponse.Msg;
            return restful;
        }
        var navConfigs = apiResponse.Data.NavConfig;

        if (navConfigs == null)
        {
            restful.Data = false;
            restful.Message = "没有接收到ITab的书签数据.";
            return restful;
        }

        var categorys = navConfigs.Select(x => new BorCategory
        {
            NavId = x.Id,
            Icon = x.Icon,
            Name = x.Name,
            Code = RuoVea.ExUtil.ExString.Str.PinYin(x.Name),
            Creator = _currentUser.UserId,
            CreateTime = DateTime.Now,
            IsDelete = 0,
            IsDisable = 0,
            Sort = 20
        }).ToList();

        categorys = categorys.Distinct().ToList();

        var x = _categoryRepository.Context.Storageable(categorys)
            .WhereColumns(x => new { x.Name, x.Creator }).ToStorage();
        await x.AsInsertable.ExecuteCommandAsync();

        var titles = navConfigs.Select(x => x.Name).Distinct().ToList();

        var categoryDatas = _categoryRepository.AsQueryable()
            .Where(x => titles.Contains(x.Name) && x.Creator == _currentUser.UserId)
            .Select(x => new BorCategory { Name = x.Name, Id = x.Id, NavId = x.NavId }).ToList();

        List<BorBookmark> contents = new();
        foreach (var nav in navConfigs)
        {
            foreach (var item in nav.Children)
            {
                //if (string.IsNullOrWhiteSpace(item.Name) || string.IsNullOrWhiteSpace(item.Url) || item.Url== "itab://add")
                if (string.IsNullOrWhiteSpace(item.Id))
                    continue;

                BorBookmark minData = new()
                {
                    NavId = item.Id,
                    Icon = item.Src,
                    Type = item.Type,
                    IconText = item.IconText,
                    Size = item.Size,
                    Url = item.Url,
                    Title = item.Name,
                    View = item.View,
                    Config = item.Config,
                    BackgroundColor = item.BackgroundColor,
                    Component = item.Component,
                    InsetType = "",
                    IsDelete = 0,
                    IsDisable = 0
                };

                minData.NavId = item.Id;

                minData.CategoryId = categoryDatas.Where(c => c.NavId == nav.Id).Select(c => c.Id).FirstOrDefault();
                minData.Creator = _currentUser.UserId;
                minData.CreateTime = DateTime.Now;
                minData.IsDisable = 0;
                minData.IsDisable = 0;
                minData.Sort = 20;
                contents.Add(minData);
            }
        }
        contents = contents.Distinct().ToList();
        var y = _thisRepository.Context.Storageable(contents).WhereColumns(x => new { x.NavId }).ToStorage();
        bool result = await y.AsInsertable.ExecuteCommandAsync() > 0 || await y.AsUpdateable.ExecuteCommandAsync() > 0;

        if (result)
        {
            restful.Data = result;
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Message = "添加失败";
            return restful;
        }
    }

    /// <summary>
    /// Itab 推送
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpPost("bookmark/pushitab")]
    public async Task<RestfulResult> PushItabAsync([FromBody] ItabExportInDto data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };
        if (data == null)
        {
            restful.Data = false;
            restful.Message = "没有接收到数据.";
            return restful;
        }
        var categoryDatas = _categoryRepository.AsQueryable().Where(x => x.Creator == _currentUser.UserId && x.PutLine == 1).ToList();
        if (categoryDatas == null)
        {
            restful.Data = false;
            restful.Message = "没有要推送的数据.";
            return restful;
        }
        List<BorBookmark> bookmarkData = await _thisRepository.AsQueryable().Where(u => u.Creator == _currentUser.UserId).ToListAsync();


        List<NavConfig> minData = categoryDatas.Select(x => new NavConfig
        {
            Icon = x.Icon,
            Id = x.NavId ?? x.Id + "",
            Name = x.Name,
            Children = bookmarkData.Where(d => d.CategoryId == x.Id)
            .Select(d => new NavItem
            {
                Id = d.NavId ?? x.Id + "",
                BackgroundColor = d.BackgroundColor,
                Component = d.Component,
                Config = d.Config,
                IconText = d.IconText,
                Name = d.Title,
                Size = d.Size,
                Src = d.Icon.IsNullOrWhiteSpace() ? "" : "data".Equals(d.Icon.Substring(0, 4)) ? "" : d.Icon,
                Type = d.Type,
                Url = d.Url,
                View = d.View,
            }).ToList()
        }).ToList();
        NavConfigDto navConfigDto = new NavConfigDto { navConfig = minData };

        string postData = JsonConvert.SerializeObject(navConfigDto, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }, NullValueHandling = NullValueHandling.Ignore });
        string update = RuoVea.ExConfig.AppSettings.app("ITab:itabUpdate");
        string responseContent = await HttpUtils.HttpPostAsync(update, postData, contentType: "application/json", headers: new Dictionary<string, string> { { "token", data.token }, { "signaturekey", data.signaturekey }, { "User-Agent", data.useragent } });
        if (string.IsNullOrWhiteSpace(responseContent))
        {
            restful.Data = false;
            restful.Message = "没有接收到ITab返回数据.";
            return restful;
        }
        ApiResponse? apiResponse = JsonConvert.DeserializeObject<ApiResponse>(responseContent);
        if (apiResponse == null)
        {
            restful.Data = false;
            restful.Message = "ITab返回数据解析失败.";
            return restful;
        }

        if (apiResponse.Code == 200)
        {
            string userUpdate = RuoVea.ExConfig.AppSettings.app("ITab:userUpdate");
            string userUpdateContent = await HttpUtils.HttpPostAsync(userUpdate, "{\"itabAsyncTime.navConfig\":" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + "}", headers: new Dictionary<string, string> { { "token", data.token },
            { "signaturekey", data.signaturekey }, { "User-Agent", data.useragent } });

            restful.Data = false;
            restful.Message = apiResponse.Msg;
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Data = null;
            restful.Message = "推送失败." + apiResponse.Msg;
            restful.Code = CodeStatus.BadRequest;
            return restful;
        }
    }
    #endregion

    #region 修改
    /// <summary>
    /// 修改
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpPost("bookmark/update")]
    public async Task<RestfulResult> UpdateAsync([FromBody] BorBookmark data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };
        if (data.Id == 0)
        {
            restful.Message = "关键信息丢失,请刷新重试.";
            return restful;
        }
        if (data.CategoryId == null || data.CategoryId <= 0)
        {
            restful.Data = false;
            restful.Message = "没有接收到分类数据.";
            return restful;
        }
        var isExist = await _thisRepository.IsAnyAsync(u => u.Id == data.Id && u.Creator == _currentUser.UserId);
        if (!isExist)
        {
            restful.Message = ErrorEnum.D3000.GetDescription(RuoVea.ExDto.Language.i18n.ResourceManager);
            return restful;
        }
        bool result = await _thisRepository.UpdateAsync(data);
        if (result)
        {
            restful.Data = result;
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Message = "修改失败";
            return restful;
        }
    }
    #endregion

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpDelete("bookmark/delete")]
    public async Task<RestfulResult> DeleteAsync([FromBody] EntityBaseId data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };

        if (data == null || data.Id == 0)
        {
            restful.Message = "删除失败";
            return restful;
        }
        bool isDelete = await _thisRepository.DeleteByIdAsync(data.Id);
        if (isDelete)
        {
            restful.Data = isDelete;
            restful.Message = "删除成功";
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Data = isDelete;
            restful.Message = "删除失败";
            return restful;
        }
    }

    #region Itab

    const string itab_token = "itab_token";
    const string itab_signatureKey = "itab_signatureKey";
    const string itab_useragent = "itab_useragent";

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    [HttpGet("bookmark/ItabInfo")]
    public async Task<RestfulResult<ItabInfoDto>> GetItabInfo()
    {
        RestfulResult<ItabInfoDto> restful = new() { Code = CodeStatus.OK };
        List<string> keys = new() { itab_token, itab_signatureKey, itab_useragent };
        var configs = await _configRepository.AsQueryable().Where(x => keys.Contains(x.Code)).ToListAsync();
        string? token = configs?.FirstOrDefault(x => x.Code == itab_token)?.Value;
        string? signatureKey = configs?.FirstOrDefault(x => x.Code == itab_signatureKey)?.Value;
        string? useragent = configs?.FirstOrDefault(x => x.Code == itab_useragent)?.Value;
        restful.Data = new ItabInfoDto { token = token, signaturekey = signatureKey, useragent = useragent };
        return restful;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    [HttpPost("bookmark/saveItabInfo")]
    public async Task<RestfulResult> SaveItabInfo([FromBody] ItabInfoDto data)
    {
        RestfulResult restful = new() { Code = CodeStatus.OK, Data = true };
        try
        {
            List<string> keys = new() { itab_token, itab_signatureKey, itab_useragent };
            var configs = await _configRepository.AsQueryable().Where(x => keys.Contains(x.Code)).ToListAsync();
            List<SysConfig> sysConfigs = new() {
                new SysConfig{GroupCode = "ITab",Sort = 301, Code = itab_token, Value = data.token, SysFlag = YesOrNot.N, Name = itab_token, Remark = "token 信息" },
                new SysConfig{GroupCode = "ITab",Sort = 302, Code = itab_signatureKey, Value = data.signaturekey, SysFlag = YesOrNot.N, Name = itab_signatureKey, Remark = "signatureKey 信息"},
                new SysConfig{GroupCode = "ITab",Sort = 303, Code = itab_useragent, Value = data.useragent, SysFlag = YesOrNot.N, Name = itab_useragent, Remark = "浏览器头 信息" },
            };
            var x = _configRepository.Context.Storageable(sysConfigs).WhereColumns(it => new { it.Code }).ToStorage();
            var i = x.AsInsertable.ExecuteCommand();
            var u = x.AsUpdateable.IgnoreColumns(x =>new { x.IsDelete,x.IsDisable,x.GroupCode,x.Sort,x.SysFlag,x.Name,x.Remark }).ExecuteCommand();
            restful.Data = true;
            return restful;
        }
        catch (Exception ex)
        {
            restful.Code = CodeStatus.BadRequest;
            restful.Message = ex.Message;
            return restful;
        }
    }
    #endregion
}

